#ifndef _AMERICO_HYBRID_ARRAY_H_
#define _AMERICO_HYBRID_ARRAY_H_

#include "DL_Debug.h"

namespace Utilities
{
	template <class Type, int MaxSize=0, int ItemIncreaseSize=0, class CountType=unsigned short, bool UsaSafeModeFlag=true>
	class HybridArray
	{
	private:
		Type myContainer[MaxSize];
		Type *myContainerPointer;
		CountType myMaxSize;
		CountType mySize;
		int myGrowthFactor;
		bool myHasGrown;
	public:
		HybridArray();
		HybridArray(const HybridArray &anHybridArray);
		~HybridArray();

		HybridArray &operator=(const HybridArray &anHybridArray);

		inline const Type &operator[](const int &anIndex) const;
		inline Type &operator[](const int &anIndex);

		inline void Add(const Type &anObject);
		inline void Insert(int anIndex, const Type &anObject);
		inline void DeleteCyclic(const Type &anObject);
		inline void DeleteCyclicAtIndex(int anItemNumber);
		inline void RemoveCyclic(const Type &anObject);
		inline void RemoveCyclicAtIndex(int anItemNumber);

		inline void RemoveAll();
		inline void DeleteAll();

		void Optimize();
		inline int Count() const;

	protected:
		inline void ReSize(CountType aNewSize);
		inline void ReSize(CountType aNewSize, const int &anIndex);

	private:
		inline void Copy(const Type *aContainer, const int &aStart, const int &anEnd);
		inline void Copy(const Type *aContainer, const int &aDestStart, const int &aStart, const int &anEnd);
	};

	template <class Type, int MaxSize, int ItemIncreaseSize, class CountType, bool UsaSafeModeFlag>
	HybridArray<Type, MaxSize, ItemIncreaseSize, CountType, UsaSafeModeFlag>::HybridArray()
	{
		myContainerPointer = myContainer;
		myHasGrown = false;
		myMaxSize = MaxSize;
		myGrowthFactor = ItemIncreaseSize;
		mySize = 0;
	}
	template <class Type, int MaxSize, int ItemIncreaseSize, class CountType, bool UsaSafeModeFlag>
	HybridArray<Type, MaxSize, ItemIncreaseSize, CountType, UsaSafeModeFlag>::HybridArray(const HybridArray &anHybridArray)
	{
		myContainerPointer = myContainer;
		myHasGrown = false;
		operator=(anHybridArray);
	}
	template <class Type, int MaxSize, int ItemIncreaseSize, class CountType, bool UsaSafeModeFlag>
	HybridArray<Type, MaxSize, ItemIncreaseSize, CountType, UsaSafeModeFlag>::~HybridArray()
	{
		if(myHasGrown)
		{
			delete [] myContainerPointer;
		}
		myContainerPointer = 0;
		myHasGrown = false;
		myMaxSize = 0;
		myGrowthFactor = 0;
		mySize = 0;
	}
	template <class Type, int MaxSize, int ItemIncreaseSize, class CountType, bool UsaSafeModeFlag>
	HybridArray<Type, MaxSize, ItemIncreaseSize, CountType, UsaSafeModeFlag> &HybridArray<Type, MaxSize, ItemIncreaseSize, CountType, UsaSafeModeFlag>::operator =(const HybridArray &anHybridArray)
	{
		if(myHasGrown)
		{
			delete [] myContainerPointer;
		}
		myHasGrown = anHybridArray.myHasGrown;
		myMaxSize = anHybridArray.myMaxSize;
		myGrowthFactor = anHybridArray.myGrowthFactor;
		mySize = anHybridArray.mySize;
		if(myHasGrown)
		{
			myContainerPointer = new Type[myMaxSize];
		}
		else
		{
			myContainerPointer = myContainer;
		}
		Copy(anHybridArray.myContainerPointer, 0, mySize);
		return *this;
	}
	template <class Type, int MaxSize, int ItemIncreaseSize, class CountType, bool UsaSafeModeFlag>
	inline const Type &HybridArray<Type, MaxSize, ItemIncreaseSize, CountType, UsaSafeModeFlag>::operator [](const int &anIndex) const
	{
		DL_CHK_ASSERT((anIndex>=0) && (anIndex<mySize), "Error: Index Out Of Bounds!");
		return myContainerPointer[anIndex];
	}
	template <class Type, int MaxSize, int ItemIncreaseSize, class CountType, bool UsaSafeModeFlag>
	inline Type &HybridArray<Type, MaxSize, ItemIncreaseSize, CountType, UsaSafeModeFlag>::operator [](const int &anIndex)
	{
		DL_CHK_ASSERT((anIndex>=0) && (anIndex<mySize), "Error: Index Out Of Bounds!");
		return myContainerPointer[anIndex];
	}
	template <class Type, int MaxSize, int ItemIncreaseSize, class CountType, bool UsaSafeModeFlag>
	inline void HybridArray<Type, MaxSize, ItemIncreaseSize, CountType, UsaSafeModeFlag>::Add(const Type &anObject)
	{
		if(mySize>=myMaxSize)
		{
			ReSize(static_cast<CountType>(myMaxSize+myGrowthFactor));
		}
		myContainerPointer[mySize++] = anObject;
	}
	template <class Type, int MaxSize, int ItemIncreaseSize, class CountType, bool UsaSafeModeFlag>
	inline void HybridArray<Type, MaxSize, ItemIncreaseSize, CountType, UsaSafeModeFlag>::Insert(int anIndex, const Type &anObject)
	{
		if(mySize>=myMaxSize)
		{
			ReSize(myMaxSize+myGrowthFactor, anIndex);
		}
		else
		{
			Copy(myContainerPointer, anIndex+1, anIndex, mySize);
		}
		myContainerPointer[anIndex] = anObject;
		++mySize;
	}
	template <class Type, int MaxSize, int ItemIncreaseSize, class CountType, bool UsaSafeModeFlag>
	inline void HybridArray<Type, MaxSize, ItemIncreaseSize, CountType, UsaSafeModeFlag>::DeleteCyclic(const Type &anObject)
	{
		for(int index=0; index<mySize; ++index)
		{
			if(myContainerPointer[index] == anObject)
			{
				DeleteCyclicAtIndex(index);
				break;
			}
		}
	}
	template <class Type, int MaxSize, int ItemIncreaseSize, class CountType, bool UsaSafeModeFlag>
	inline void HybridArray<Type, MaxSize, ItemIncreaseSize, CountType, UsaSafeModeFlag>::DeleteCyclicAtIndex(int anItemNumber)
	{
		DL_CHK_ASSERT((anItemNumber>=0) && (anItemNumber<mySize), "Error: Index Out Of Bounds!");
		delete myContainerPointer[anItemNumber];
		RemoveCyclicAtIndex(anItemNumber);
	}
	template <class Type, int MaxSize, int ItemIncreaseSize, class CountType, bool UsaSafeModeFlag>
	inline void HybridArray<Type, MaxSize, ItemIncreaseSize, CountType, UsaSafeModeFlag>::DeleteAll()
	{
		for(int index=0; index<mySize; index++)
		{
			delete myContainerPointer[index];
		}
		mySize = 0;
	}
	template <class Type, int MaxSize, int ItemIncreaseSize, class CountType, bool UsaSafeModeFlag>
	inline void HybridArray<Type, MaxSize, ItemIncreaseSize, CountType, UsaSafeModeFlag>::RemoveCyclic(const Type &anObject)
	{
		for(int index=0; index<mySize; ++index)
		{
			if(myContainerPointer[index] == anObject)
			{
				RemoveCyclicAtIndex(index);
				break;
			}
		}
	}
	template <class Type, int MaxSize, int ItemIncreaseSize, class CountType, bool UsaSafeModeFlag>
	inline void HybridArray<Type, MaxSize, ItemIncreaseSize, CountType, UsaSafeModeFlag>::RemoveCyclicAtIndex(int anItemNumber)
	{
		DL_CHK_ASSERT((anItemNumber>=0) && (anItemNumber<mySize), "Error: Index Out Of Bounds!");
		myContainerPointer[anItemNumber] = myContainerPointer[--mySize];
	}
	template <class Type, int MaxSize, int ItemIncreaseSize, class CountType, bool UsaSafeModeFlag>
	inline void HybridArray<Type, MaxSize, ItemIncreaseSize, CountType, UsaSafeModeFlag>::RemoveAll()
	{
		mySize = 0;
	}
	template <class Type, int MaxSize, int ItemIncreaseSize, class CountType, bool UsaSafeModeFlag>
	inline void HybridArray<Type, MaxSize, ItemIncreaseSize, CountType, UsaSafeModeFlag>::Optimize()
	{
		if(myHasGrown)
		{
			ReSize(mySize);
			myGrowthFactor = 1;
		}
	}
	template <class Type, int MaxSize, int ItemIncreaseSize, class CountType, bool UsaSafeModeFlag>
	inline int HybridArray<Type, MaxSize, ItemIncreaseSize, CountType, UsaSafeModeFlag>::Count() const
	{
		return mySize;
	}
	template <class Type, int MaxSize, int ItemIncreaseSize, class CountType, bool UsaSafeModeFlag>
	inline void HybridArray<Type, MaxSize, ItemIncreaseSize, CountType, UsaSafeModeFlag>::ReSize(CountType aNewSize)
	{
		Type *tmp = myContainerPointer;
		myContainerPointer = new Type[aNewSize];
		Copy(tmp, 0, mySize);
		if(myHasGrown)
		{
			delete tmp;
		}
		else
		{
			myHasGrown = true;
		}
		tmp = 0;
		myMaxSize = aNewSize;
		myHasGrown = true;
	}
	template <class Type, int MaxSize, int ItemIncreaseSize, class CountType, bool UsaSafeModeFlag>
	inline void HybridArray<Type, MaxSize, ItemIncreaseSize, CountType, UsaSafeModeFlag>::ReSize(CountType aNewSize, const int &anIndex)
	{
		DL_CHK_ASSERT((anIndex>=0) && (anIndex<=mySize), "Error: Index Out Of Bounds!");
		Type *tmp = myContainerPointer;
		myContainerPointer = new Type[aNewSize];
		Copy(tmp, 0, anIndex);
		Copy(tmp+anIndex, anIndex+1, 0, mySize+1);
		if(myHasGrown)
		{
			delete tmp;
		}
		else
		{
			myHasGrown = true;
		}
		tmp = 0;
		myMaxSize = aNewSize;
		myHasGrown = true;
	}
	template <class Type, int MaxSize, int ItemIncreaseSize, class CountType, bool UsaSafeModeFlag>
	inline void HybridArray<Type, MaxSize, ItemIncreaseSize, CountType, UsaSafeModeFlag>::Copy(const Type *aContainer, const int &aStart, const int &anEnd)
	{
		Copy(aContainer, 0, aStart, anEnd);
	}
	template <class Type, int MaxSize, int ItemIncreaseSize, class CountType, bool UsaSafeModeFlag>
	inline void HybridArray<Type, MaxSize, ItemIncreaseSize, CountType, UsaSafeModeFlag>::Copy(const Type *aContainer, const int &aDestStart, const int &aStart, const int &anEnd)
	{
		if(UsaSafeModeFlag)
		{
			memmove(myContainerPointer+aDestStart, aContainer+aStart, (anEnd-aStart)*sizeof(Type));
		}
		else
		{
			for(int index=aStart; index<anEnd; ++index)
			{
				myContainerPointer[index] = aContainer[index];
			}
		}
	}
};
namespace Utils=Utilities;

#endif
